package cn.com.cifi.mars.util;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import cn.com.cifi.mars.common.redis.RedisTemplateUtil;
import cn.com.cifi.mars.constant.Constants;
import lombok.extern.slf4j.Slf4j;

/**
 * 
 * @Description：Redis共享锁
 * @author：yyd
 * @date：2020年6月5日 下午2:53:36
 */
@Slf4j
@Component
public class SynchrolockUtil {
    
    @Autowired
    private RedisTemplateUtil redisClientTemplate;

    private String uuid;
    
    @PostConstruct
    public void init() {
        uuid = UUID.randomUUID().toString();
    }

    /**
       * 根据传入key值，判断缓存中是否存在该key
        * 存在-已上锁：判断retryType，轮询超时，或直接返回，返回ture
        * 不存在-未上锁：将该key放入缓存，返回false
     * @param key
     * @param retryType 当遇到上锁情况时  1：轮询；0：直接返回
     * @return
     */
    public boolean islocked(String key){
        boolean flag = true;
        //请求超时时间 毫秒
        Long requestTimeOut = Constants.ReTryTimeOut;
        //缓存中key的失效时间 秒
        Integer keyTimeout = Constants.KeyTimeOut;
        //首次调用时间  
        Long startTime = System.currentTimeMillis(); 
        
        if(isLockedInRedis(key,keyTimeout)){
            //采用轮询方式等待
            while (true) {
                log.info("====已被占用，开始轮询====");
                try {
                    Thread.sleep(Constants.ReTryTime);
                } catch (InterruptedException e) {
                    log.error("线程睡眠异常:"+e.getMessage(), e);
                    return flag;
                }
                
                //当前调用时间
                Long currentTime = System.currentTimeMillis(); 
                long interval = currentTime - startTime;
                if (interval > requestTimeOut) {
                    log.info("====请求超时====");
                    return flag;
                }
                                
                if(!isLockedInRedis(key,keyTimeout)){
                    log.info("====轮询结束，添加同步锁====");
                    flag = false;
                    break;
                }
            }            
        }else{
            log.info("====未被占用，添加同步锁====");
            flag = false;
        }
        return flag;
    }
    
    /**
     * 在缓存中查询key是否存在
     * 若存在则返回true;
     * 若不存在则将key放入缓存，设置过期时间，返回false
     * @param key
     * @param keyTimeout key超时时间单位是秒
     * @return
     */
    boolean isLockedInRedis(String key,int keyTimeout){
        log.info("====查询key是否存在====");
        boolean isExist = false; 
       
        boolean lockFlag = this.redisClientTemplate.tryLock(key, uuid,keyTimeout*1000L,TimeUnit.SECONDS);
       
        if(lockFlag){
            this.redisClientTemplate.expire(key, keyTimeout*1000L,TimeUnit.SECONDS);
            log.info("====未锁，加锁成功====");
            isExist = false;
        }else{
            log.info("====已锁====");
            isExist = true;
        }
        return isExist;
    }
    
    /**
     * 根据传入key，进行解锁
     * @param key
     * @return
     */
    public void unlock(String key){
        this.redisClientTemplate.delete(key);
    }   
}
